import { Subject, from, fromEvent, of } from "rxjs";
import {
  catchError,
  debounceTime,
  distinctUntilChanged,
  filter,
  map,
  startWith,
  switchMap,
  tap,
} from "rxjs/operators";

type StatusType = "idle" | "validating" | "success" | "error";

function useChangeCheck(inputElement: JQuery<HTMLInputElement>) {
  // 状态 (Observable) 管理(构造器)
  const statusSubject = new Subject<StatusType>();
  // 创建一个默认状态(Observable)为 idle 的 Observable
  const currentStatus$ = statusSubject.asObservable().pipe(startWith("idle"));
  // 创建一个新的 Observable，当状态为 'idle' 或 'success' 时为 true
  const isIdleOrSuccess$ = currentStatus$.pipe(
    map((status) => status === "idle" || status === "success"),
  );

  // 1. 监听 input 事件
  const input$ = fromEvent(inputElement, "input").pipe(
    map((event: Event) => (event.target as HTMLInputElement).value),
    distinctUntilChanged(),
  );

  // 2. 验证输入是否符合规则
  const validatedInput$ = input$.pipe(
    map((value) => {
      // 检查是否只包含 A-Za-z._-
      const isValid = /^[\w.-]*$/.test(value);
      if (!isValid) {
        // 如果不合法，过滤掉非法字符
        // eslint-disable-next-line unicorn/prefer-string-replace-all
        return value.replace(/[^\w.-]/g, "");
      }
      return value;
    }),
    // 更新输入框的值（如果需要过滤）
    tap((filteredValue) => {
      if (filteredValue !== inputElement[0].value) {
        inputElement[0].value = filteredValue;
      }
    }),
    // 转换值：将 . 和 _ 转为 -
    // eslint-disable-next-line unicorn/prefer-string-replace-all
    map((value) => value.replace(/[._]/g, "-")),
    // 把开头或结尾的 - 去掉
    map((value) => value.replace(/^-/, "")),
    map((value) => value.replace(/-$/, "")),
    distinctUntilChanged(),
  );

  // 3. 防抖处理并在停止输入2秒后发出请求
  const debouncedValidation$ = validatedInput$.pipe(
    debounceTime(2000),
    // 过滤空值
    filter<string>((value) => value !== ""),
    tap(() => statusSubject.next("validating")),
  );
  const request$ = debouncedValidation$.pipe<string>(
    switchMap((value) =>
      from(simulateApiRequest(value)).pipe(
        tap(() => statusSubject.next("success")),
        catchError((err) => {
          statusSubject.next("error");
          return of(err);
        }),
      ),
    ),
  );

  // 订阅处理
  request$.subscribe({
    next: (result) => console.log("Validation result:", result),
    error: (err) => console.error("Validation error:", err),
  });

  // 状态 observable 以便其他地方使用
  return { currentStatus$, isIdleOrSuccess$ };
}
// 模拟 API 请求
function simulateApiRequest(value: string) {
  // 模拟网络延迟
  const delay = Math.random() * 1000 + 500;
  // 模拟随机成功/失败
  const shouldFail = Math.random() > 0.8;

  return new Promise<{
    valid: boolean;
    value: string;
  }>((resolve, reject) => {
    setTimeout(() => {
      if (shouldFail) {
        reject(new Error("Validation failed"));
      } else {
        resolve({ valid: true, value });
      }
    }, delay);
  });
}
/// //////////////////////////////// ///
/// //////////////////////////////// ///
// 示例2
/// //////////////////////////////// ///
/// //////////////////////////////// ///

function useChangeCheck2(
  inputElement: JQuery<HTMLInputElement>,
  statusElement = document.getElementById("status"),
) {
  // 用于表示加载状态的 Subject
  const isLoading$ = new Subject<boolean>();

  if (inputElement) {
    fromEvent(inputElement, "input")
      .pipe(
        // 1. 获取输入框的值
        map((event) => (event.target as HTMLInputElement).value),
        // 2. 过滤符合正则表达式的值
        filter((value) => /^[A-Z._-]+$/i.test(value)),
        // 3. 转换值
        map((value) => {
          // eslint-disable-next-line unicorn/prefer-string-replace-all
          let transformedValue = value.replace(/[._]/g, "-");
          // 如果转换后的值全由 '-' 构成，则置空
          if (/^-+$/.test(transformedValue)) {
            transformedValue = "";
          }
          return transformedValue;
        }),
        // 4. 判断转换后的值是否为空，如果为空则不发出
        filter((transformedValue) => transformedValue !== ""),
        // 5. 防抖：停止输入2秒后才发出值
        debounceTime(2000),
        // 6. 只有当值发生变化时才继续
        distinctUntilChanged(),
        // 7. 在发出请求前设置 isLoading 为 true
        tap(() => isLoading$.next(true)),
        // 8. 切换到新的 Observable，模拟校验请求
        switchMap((transformedValue) =>
          // 模拟一个异步校验请求，这里用 of() 和 setTimeout() 模拟
          of(transformedValue).pipe(
            tap((val) => console.log(`发起校验请求: ${val}`)),
            // 模拟网络延迟
            debounceTime(1000), // 模拟请求耗时
            map((val) => `校验结果：${val} - 通过！`), // 模拟校验成功结果
            catchError((error) => {
              console.error("校验请求失败:", error);
              return of(`校验失败：${error.message}`); // 返回一个错误信息
            }),
          ),
        ),
        // 9. 请求完成后设置 isLoading 为 false
        tap(() => isLoading$.next(false)),
      )
      .subscribe((result) => {
        console.log("最终校验结果:", result);
        // 可以在这里更新 UI，显示校验结果
      });
  } else {
    console.error('未找到 ID 为 "myInput" 的元素。');
  }

  // 订阅加载状态, 可以分离到其他地方
  isLoading$.subscribe((loading) => {
    console.log("加载状态:", loading ? "正在请求中..." : "空闲");
    // 可以在这里更新 UI，例如显示/隐藏加载指示器;
    if (statusElement) {
      statusElement.textContent = loading ? "正在请求中..." : "空闲";
    }
  });
  return { isLoading$ };
}

export { useChangeCheck2, useChangeCheck };
